package cn.cmvideo.springboot.nio;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class NioServerWork implements Runnable
{
	private Logger log = LoggerFactory.getLogger(NioServerWork.class);
	
	private Selector selector;
	private ServerSocketChannel channel;

	public NioServerWork(int port)
	{
		try
		{
			selector = Selector.open(); // 打开多路复用器
			channel = ServerSocketChannel.open(); // 打开socketChannel
			channel.configureBlocking(false); // 配置通道为非阻塞的状态
			channel.socket().bind(new InetSocketAddress(port), 1024); // 通道socket绑定地址和端口
			channel.register(selector, SelectionKey.OP_ACCEPT); // 将通道channel在多路复用器上注册为接收状态
		} catch (IOException e)
		{
			e.printStackTrace();
		}
	}

	@Override
	public void run()
	{
		log.info("NIO 服务  run()...");
		while (true)
		{
			try
			{
				selector.select(1000);
				// 获取多路复用器的事件值selectionKey
				Set<SelectionKey> selectedKeys = selector.selectedKeys();
				Iterator<SelectionKey> iterator = selectedKeys.iterator();
				while (iterator.hasNext())
				{
					SelectionKey key = null;
					key = iterator.next();
					try
					{
						// 根据SelectionKey的值进行相应的读写操作
						handleinput(key);
					} catch (Exception e)
					{
						if (key != null)
						{
							key.cancel();
							if (key.channel() != null)
							{
								key.channel().close();
							}
						}
					}
					
					iterator.remove();
				}
			} catch (IOException e)
			{
				log.info("NIO 服务  run  catch IOException...");
				e.printStackTrace();
				System.exit(1);
			}
		}

	}

	public void handleinput(SelectionKey key) throws IOException
	{
		if (key.isValid())
		{
			if (key.isAcceptable())
			{
				ServerSocketChannel ssc = (ServerSocketChannel) key.channel(); // 获取key值所对应的channel
				SocketChannel sc = ssc.accept(); 
				sc.configureBlocking(false); // 设置为接收非阻塞通道
				sc.register(selector, SelectionKey.OP_READ); // 把这个通道注册为OP_READ 
			}
			if (key.isReadable())
			{
				SocketChannel sc = (SocketChannel) key.channel(); // 获取key对应的channel
				
				ByteBuffer buffer = ByteBuffer.allocate(1024);
				int readbytes = sc.read(buffer); // 从channel中读取byte数据并存放到buffer
				if (readbytes > 0)
				{
					buffer.flip();
					byte[] bytes = new byte[buffer.remaining()];
					buffer.get(bytes);
					String str = new String(bytes, "UTF-8");
					log.info("NIO 客户端套接字:{},服务器接受到命令:{}",sc.getRemoteAddress(),str);

					// 给客户端发送数据
					String currenttime = "1".equalsIgnoreCase(str)
							? new java.util.Date(System.currentTimeMillis()).toString() : "bad order";
					doWrite(sc, currenttime);
				} else if (readbytes < 0)
				{
					key.cancel();
					sc.close();
				}
			}

		}

	}

	public void doWrite(SocketChannel sc, String currenttime) throws IOException
	{
		if (currenttime != null && currenttime.trim().length() > 0)
		{
			byte[] bytes = currenttime.getBytes();
			ByteBuffer buffer = ByteBuffer.allocate(bytes.length);
			buffer.put(bytes);
			buffer.flip();
			sc.write(buffer);
		}
	}
}
